/* 
** Copyright (C) 2006  sejishikong <sejishikong@263.net>
** Authors:    sejishikong <sejishikong@263.net>
**             Wei Lian <lianwei3@gmail.com> 
** Maintainer: Wei Lian
**    This program is free software; you can redistribute it and/or modify
**    it under the terms of the GNU General Public License Version 2 as
**    published by the Free Software Foundation;
**
**    This program is distributed in the hope that it will be useful,
**    but WITHOUT ANY WARRANTY; without even the implied warranty of
**    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**    GNU General Public License for more details.
**
**    You should have received a copy of the GNU General Public License
**    along with this program; if not, write to the Free Software
**    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
*/
#include "header.h"
#include "sopfork.h"
#include "sys.h"
#include "tabwidget.h"
#include "mystatusbar.h"

SopFork::SopFork(TabWidget * tw, QWidget * parent,
		 const char *name):QHBox(parent, name), tabwidget(tw)
{
    sop = new QProcess(this);
    connect(sop, SIGNAL(readyReadStdout()), this, SLOT(parseStdout()));
    connect(sop, SIGNAL(processExited()), this, SLOT(onSopExit()));

    snstatus = 0;

    echotimer = new QTimer(this);
    connect(echotimer, SIGNAL(timeout()), this, SLOT(echo()));

    ///row
    statusbar = new MyStatusBar(this);
}


SopFork::~SopFork()
{
    if (snstatus)
	delete snstatus;
    killSop();
}

static QString reduceLabelLength(const QString & s)
{
    uint maxLength = 8;
    QString str = s;
    if (str.length() <= maxLength)
	return str;
    str = str.left(maxLength);
//    str += "...";
    return str;
}


////fork new process
bool SopFork::forkSop(QString url, QString name, QString type)
{
    channelurl = url;
    channelname = name;
    channeltype = type;

    tabwidget->setTabLabel(parentWidget(), reduceLabelLength(channelname));
    statusbar->showMessage(tr("Connecting..."));

    int i;
    char inport[8];
    int sock;
    ///choose inport and outport number
    for (i = 8000; i < 9000; i++) {
	sock = Sys::connect_to_server("127.0.0.1", i);
	if (sock == -1)
	    break;
	else if (sock >= 0)
	    ::close(sock);
    }
    sprintf(inport, "%d", i);

    for (i = 9000; i < 10000; i++) {
	sock = Sys::connect_to_server("127.0.0.1", i);
	if (sock == -1)
	    break;
	else if (sock >= 0)
	    ::close(sock);
    }
    sprintf(outport, "%d", i);
    ////    
    sop->clearArguments();
    sop->addArgument("sp-sc");
    sop->addArgument(url);
    sop->addArgument(inport);
    sop->addArgument(outport);
    return sop->start();
}



////kill process
void SopFork::killSop()
{
    if (sop->isRunning()) {
//      sop->tryTerminate ();
	sop->kill();
    }
}



/////////////slots
void SopFork::onSopExit()
{
    statusbar->showMessage("");
    channelname = "";
    channelurl = "";
    tabwidget->setTabLabel(parentWidget(), tr("record"));
}


void SopFork::parseStdout()
{
    QString str = QString(sop->readStdout());

    if (snstatus == 0) {
	if (str.contains("hook_sc") || str.contains("downloadRate=")) {
	    //create socket
	    int sockfd =
		Sys::connect_to_server("127.0.0.1", atoi(outport));
	    if (sockfd < 0) {
		fprintf(stderr,
			"failed to create socket, return err %d\n",
			sockfd);
		return;
	    }
	    ///bind QSocketNotifier to socket
	    snstatus =
		new QSocketNotifier(sockfd, QSocketNotifier::Read, this);
	    connect(snstatus, SIGNAL(activated(int)),
		    SLOT(streamReady(int)));
	    write(sockfd, "state\ns\n", sizeof("state\ns\n"));
	    write(sockfd, "state\ns\n", sizeof("state\ns\n"));
	} else if (str.contains("detect MTU"))
	    statusbar->showMessage(tr("Waiting..."));
    }
}


void SopFork::streamReady(int fd)
{
    char buff[64];
    memset(buff, 0, sizeof(buff));

    int red = 0, size, ret;
    size = sizeof(buff);
    while (1) {
	ret =::read(fd, buff + red, size);
	if (ret <= 0)		///server shutdown
	{
	    if (ret < 0)
		perror("status socketnotifier");
	    //close socket and delete socket noitifier
	    ::close(fd);
	    delete snstatus;
	    snstatus = 0;
	    ///stop timer
	    echotimer->stop();
	    ///change statusbar interface
	    return;
	}
	if (strstr(buff, "\n"))
	    break;

	red += ret;
	size -= ret;
    }

    if (buff[0] != 10) {
	char *savept;
	strtok_r(buff, "\n", &savept);

	int value[6];
	value[0] = atoi(strtok_r(buff, " ", &savept));
	for (int i = 1; i < 6; i++) {
	    value[i] = atoi(strtok_r(NULL, " ", &savept));
	    if (i < 5)
		value[i] = value[i] / 1024;
	}

	static const char format[][10] =
	    { "%d%%", "ur=%dk", "dr=%dk", "us=%dk", "ds=%dk",
	    "peers=%d"
	};

	QString str[6];

	for (int i = 0; i < 6; i++) {
	    sprintf(buff, format[i], value[i]);
	    str[i] = buff;
	}
	statusbar->showMessage(str);


    } else
	printf("buff=10\n");

    ///singleshot
    echotimer->start(1000, true);
}


void SopFork::echo()
{
    if (tabwidget->indexOf(parentWidget()) ==
	tabwidget->currentPageIndex()) {
	write(snstatus->socket(), "s\n", sizeof("s\n"));
    } else
	echotimer->start(1000, true);
}
